<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>微信群视频聊天</title>
		<link rel="stylesheet" href="./css/toast.css" />
		<link rel="stylesheet" href="./css/chartVideo.css" />
		<style>
			/* 新增群聊样式 */
			.video-container {
				position: relative;
				width: 100%;
				height: 100vh;
				background-color: #000;
				overflow: hidden;
			}

			.main-video {
				width: 100%;
				height: 100%;
				object-fit: cover;
			}

			.member-videos {
				position: absolute;
				bottom: 120px;
				left: 0;
				right: 0;
				display: flex;
				flex-wrap: wrap;
				justify-content: center;
				gap: 10px;
				padding: 10px;
				z-index: 10;
			}

			.member-video-item {
				width: 80px;
				height: 120px;
				position: relative;
				border-radius: 5px;
				overflow: hidden;
				background-color: #333;
			}

			.member-video {
				width: 100%;
				height: 100%;
				object-fit: cover;
			}

			.member-info {
				position: absolute;
				bottom: 0;
				left: 0;
				right: 0;
				background: rgba(0, 0, 0, 0.5);
				color: white;
				padding: 3px;
				font-size: 10px;
				display: flex;
				justify-content: space-between;
			}

			.member-name {
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
			}

			.member-status {
				display: flex;
				align-items: center;
			}

			.speaking-indicator {
				width: 8px;
				height: 8px;
				border-radius: 50%;
				background-color: #09bb07;
				margin-right: 3px;
				display: none;
			}

			.speaking .speaking-indicator {
				display: block;
			}

			.muted .member-video {
				opacity: 0.5;
			}

			.call-info {
				position: absolute;
				top: 20px;
				left: 0;
				right: 0;
				text-align: center;
				color: white;
				z-index: 10;
			}

			.call-title {
				font-size: 18px;
				margin-bottom: 5px;
			}

			.call-status {
				font-size: 14px;
				color: #ccc;
			}

			.control-buttons {
				position: fixed;
				bottom: 20px;
				left: 0;
				right: 0;
				display: flex;
				justify-content: center;
				gap: 15px;
				padding: 0 20px;
				z-index: 10;
			}

			.control-button {
				display: flex;
				flex-direction: column;
				align-items: center;
				background: rgba(255, 255, 255, 0.2);
				border: none;
				border-radius: 50%;
				width: 60px;
				height: 60px;
				color: white;
				font-size: 12px;
			}

			.control-button i {
				font-size: 24px;
				margin-bottom: 5px;
			}

			.control-button.active {
				background: rgba(9, 187, 7, 0.3);
			}

			.control-button.end-call {
				background: #f44336;
			}

			.incoming-call {
				position: fixed;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background-color: rgba(0, 0, 0, 0.8);
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				z-index: 100;
				color: white;
			}

			.caller-avatar {
				width: 150px;
				height: 150px;
				border-radius: 50%;
				object-fit: cover;
				margin-bottom: 20px;
			}

			.caller-name {
				font-size: 24px;
				margin-bottom: 10px;
			}

			.call-status {
				font-size: 16px;
				color: #ccc;
				margin-bottom: 30px;
			}

			.call-members {
				font-size: 14px;
				color: #aaa;
				margin-bottom: 40px;
			}

			.answer-buttons {
				display: flex;
				gap: 50px;
			}

			.decline-call,
			.accept-call {
				width: 60px;
				height: 60px;
				border-radius: 50%;
				display: flex;
				align-items: center;
				justify-content: center;
				cursor: pointer;
			}

			.decline-call {
				background-color: #f44336;
			}

			.accept-call {
				background-color: #09bb07;
			}

			.button-icon {
				font-size: 24px;
				color: white;
			}

			.loading {
				position: fixed;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background-color: rgba(0, 0, 0, 0.8);
				display: none;
				align-items: center;
				justify-content: center;
				color: white;
				font-size: 18px;
				z-index: 100;
			}
		</style>
	</head>
	<body>
		<!-- 群视频通话界面 -->
		<div class="video-container" id="groupVideoCall">
			<!-- 主视频 -->
			<video class="main-video" id="mainVideo" autoplay playsinline></video>

			<!-- 成员视频列表 -->
			<div class="member-videos" id="memberVideos">
				<!-- 成员视频将通过JS动态添加 -->
			</div>

			<div class="call-info">
				<div class="call-title" id="groupTitle">微信群视频聊天</div>
				<div class="call-status" id="callTime">00:00:00</div>
			</div>

			<div class="control-buttons">
				<button class="control-button mute" id="muteBtn">
					<img class="fa" src="./images/microphone.svg" alt="" />
					<span>静音</span>
				</button>
				<button class="control-button speaker" id="speakerBtn">
					<img class="fa" src="./images/volume-up.svg" alt="" />
					<span>扬声器</span>
				</button>
				<button class="control-button switch-camera" id="changeBtn">
					<img class="fa" src="./images/camera-retro.svg" alt="" />
					<span>切换</span>
				</button>
				<button class="control-button invite" id="inviteBtn">
					<img class="fa" src="./images/user-plus.svg" alt="" />
					<span>邀请</span>
				</button>
				<button class="control-button end-call" id="endCallBtn">
					<img class="fa" src="./images/phone-slash.svg" alt="" />
					<span>挂断</span>
				</button>
			</div>
		</div>

		<!-- 来电界面 -->
		<div id="incomingGroupCall">
			<div class="incoming-call">
				<img src="https://via.placeholder.com/150/333/666" alt="头像" class="caller-avatar" id="groupAvatar">
				<div class="caller-name" id="groupCallerName">微信群聊</div>
				<div class="call-status">视频通话邀请...</div>
				<div class="call-members">
					<span id="groupMembersText">成员: 张三, 李四, 王五</span>
				</div>

				<div class="answer-buttons">
					<div class="decline-call" id="declineCallBtn">
						<img class="fa" src="./images/phone-slash.svg" alt="" />
					</div>
					<div class="accept-call" id="acceptCallBtn">
						<img class="fa" src="./images/phone.svg" alt="" />
					</div>
				</div>
			</div>
		</div>

		<!-- 加载指示器 -->
		<div class="loading" id="loadingIndicator">正在连接...</div>

		<!-- toast提示 -->
		<div id="toast" class="toast hide">
			<div class="toast-content">
				<p id="toastMessage"></p>
			</div>
		</div>

		<script type="text/javascript" src="./js/uni.webview.1.5.2.js"></script>
		<script src="./js/AgoraRTC_N-4.8.0.js"></script>
		<script>
			// 在初始化代码前加入
			window.addEventListener('unhandledrejection', (event) => {
			  if (event.reason?.message?.includes("Failed to execute 'getStats'")) {
			    event.preventDefault(); // 阻止控制台报错
			    console.warn("[AgorRTC 内部错误已忽略]", event.reason);
			  }
			});
			// 方案1：等待 UniApp 环境就绪事件
			document.addEventListener('UniAppJSBridgeReady', () => {
				console.log('UniAppJSBridgeReady:'); // 处理接收到的消息
			});

			// 发送给外层信息
			function sendToUniApp(message) {
				console.log("向外层发送消息:");
				// 方法1：标准 UniApp 方式
				if (window.uni?.postMessage) {
					uni.postMessage({
						data: message
					});
					return;
				}

				// 方法2：URL Scheme 回退
				try {
					location.href = `uniwebview://postMessage?data=${encodeURIComponent(JSON.stringify(message))}`;
				} catch (e) {
					console.error('URL Scheme 失败:', e);
				}

				// 方法3：通过 parent 通信（如果是 iframe 嵌套）
				if (window.parent !== window) {
					window.parent.postMessage({
						type: 'webview',
						data: message
					}, '*');
				}
			}

			// 工具函数：解析 URL 参数
			function getUrlParams() {
				const urlParams = new URLSearchParams(window.location.search);
				const paramsObject = {};
				urlParams.forEach((value, key) => {
					paramsObject[key] = value;
				});
				return paramsObject;
			}

			const params = getUrlParams();
			console.log("params 参数:", params);

			let isSelf = params.isSelf;
			if (isSelf == true) {
				document.getElementById('acceptCallBtn').style.display = 'none';
			} else {
				document.getElementById('acceptCallBtn').style.display = 'flex';
			}

			// 获取DOM元素
			const incomingCall = document.getElementById('incomingGroupCall');
			const groupVideoCall = document.getElementById('groupVideoCall');
			const acceptCallBtn = document.getElementById('acceptCallBtn');
			const declineCallBtn = document.getElementById('declineCallBtn');
			const endCallBtn = document.getElementById('endCallBtn');
			const muteBtn = document.getElementById('muteBtn');
			const speakerBtn = document.getElementById('speakerBtn');
			const changeBtn = document.getElementById('changeBtn');
			const mainVideo = document.getElementById('mainVideo');
			const memberVideos = document.getElementById('memberVideos');
			const loadingIndicator = document.getElementById('loadingIndicator');
			const groupTitle = document.getElementById('groupTitle');
			const groupCallerName = document.getElementById('groupCallerName');
			const groupMembersText = document.getElementById('groupMembersText');
			const groupAvatar = document.getElementById('groupAvatar');
			const inviteBtn = document.getElementById('inviteBtn');		
			const channelInfo = JSON.parse(decodeURIComponent(params.channelInfo));
			const userInfo = JSON.parse(params.userInfo);
			const groupInfo = JSON.parse(params.groupInfo || '{}'); // 新增群组信息

			console.log('channelInfo', channelInfo);
			console.log('userInfo', userInfo);
			console.log('groupInfo', groupInfo);

			// 设置群聊信息
			if (groupInfo.groupName) {
				groupTitle.innerText = groupInfo.groupName;
				groupCallerName.innerText = groupInfo.groupName;

				if (groupInfo.avatar) {
					groupAvatar.src = groupInfo.avatar;
				}

				if (groupInfo.members) {
					const membersText = groupInfo.members.map(m => m.name).join(', ');
					groupMembersText.innerText = `成员: ${membersText}`;
				}
			}

			const userId = userInfo.id;
			let currentMainSpeaker = null; // 当前主说话人ID

			// AgoraRTC 客户端和轨道管理
			let client = null;
			let localVideoTrack = null;
			let localAudioTrack = null;
			let remoteUsers = {}; // 存储远程用户信息
			let cameraId = null; // 当前摄像头ID
			let isFrontCamera = true; // 是否前置摄像头

			// 模拟来电铃声
			function playRingtone() {
				console.log("播放来电铃声...");
			}

			// 接听电话
			acceptCallBtn.addEventListener('click', async function() {
				await joinChannel();
			});

			// 拒接电话
			declineCallBtn.addEventListener('click', function() {
				incomingCall.style.display = 'none';
				console.log("已拒绝群视频通话");
				const call_request = {
					callerId: "caller",
					status: false,
					timestamp: Date.now(),
					userId: userId,
					type: 'group_video'
				};
				sendToUniApp(call_request);
			});

			// 挂断电话
			endCallBtn.addEventListener('click', function() {
				handeUp(userId);
			});

			// 静音按钮
			muteBtn.addEventListener('click', async function() {
				this.classList.toggle('active');
				if (localAudioTrack) {
					if (this.classList.contains('active')) {
						// this.querySelector('i').className = 'fas fa-microphone-slash';
						this.querySelector('img').src = './images/microphone-slash.svg'
						localAudioTrack.setVolume(0);
						console.log("已静音");
					} else {
						// this.querySelector('i').className = 'fas fa-microphone';
						this.querySelector('img').src = './images/microphone.svg'
						localAudioTrack.setVolume(100);
						console.log("取消静音");
					}
				}
			});

			// 扬声器按钮
			speakerBtn.addEventListener('click', async function() {
				this.classList.toggle('active');
				if (this.classList.contains('active')) {
					// this.querySelector('i').className = 'fas fa-volume-up';
					this.querySelector('img').src = './images/volume-up.svg'
					console.log("扬声器已开启");
					updateRemoteAudioVolume(100);
				} else {
					// this.querySelector('i').className = 'fas fa-volume-off';
					this.querySelector('img').src = './images/volume-off.svg'
					console.log("扬声器已关闭");
					updateRemoteAudioVolume(50);
				}
			});

			// 切换摄像头按钮
			changeBtn.addEventListener('click', async function() {
				if (!localVideoTrack) return;

				try {
					// showLoading("正在切换摄像头...");
					showToast("正在切换摄像头...")

					// 获取所有摄像头设备
					const devices = await AgoraRTC.getCameras();
					if (devices.length < 2) {
						showToast("未找到其他摄像头");
						return;
					}

					// 关闭当前摄像头
					await localVideoTrack.setEnabled(false);

					// 切换摄像头
					isFrontCamera = !isFrontCamera;
					const facingMode = isFrontCamera ? "user" : "environment";

					// 创建新的视频轨道
					const newVideoTrack = await AgoraRTC.createCameraVideoTrack({
						facingMode: facingMode
					});

					// 替换本地视频轨道
					await client.unpublish([localVideoTrack]);
					localVideoTrack.close();
					localVideoTrack = newVideoTrack;

					// 发布新的视频轨道
					await client.publish([localVideoTrack]);

					// 更新本地视频显示
					const localVideoElement = document.getElementById(`local-video-${userId}`);
					if (localVideoElement) {
						localVideoElement.srcObject = new MediaStream([localVideoTrack.getMediaStreamTrack()]);
					}

					console.log("摄像头切换成功");
				} catch (error) {
					console.error("切换摄像头失败:", error);
					showToast("切换摄像头失败");
				} finally {
					hideLoading();
				}
			});

			// 用户挂断
			function handeUp(userUid) {
				groupVideoCall.style.display = 'none';
				console.log("群视频通话已结束");
				const call_request = {
					callerId: "handelUp",
					status: false,
					timestamp: Date.now(),
					userId: userUid,
					type: 'group_video'
				};
				sendToUniApp(call_request);
				stopCallTimer();
				leaveChannel();
			}

			// 开始通话计时器
			let callTimer = null;

			function startCallTimer() {
				let seconds = 0;
				const timerElement = document.getElementById('callTime');

				callTimer = setInterval(function() {
					seconds++;
					const hours = Math.floor(seconds / 3600);
					const minutes = Math.floor((seconds % 3600) / 60);
					const secs = seconds % 60;

					timerElement.textContent =
						`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
				}, 1000);
			}

			// 停止通话计时
			function stopCallTimer() {
				if (callTimer) {
					clearInterval(callTimer);
					callTimer = null;
				}
			}

			// 页面加载时播放铃声
			window.addEventListener('load', function() {
				playRingtone();
			});

			// 加入频道
			async function joinChannel() {
				const appId = channelInfo.appId.trim() || null;
				const channel = channelInfo.channel.trim() || null;
				const token = channelInfo.token.trim() || null;
				const userId = userInfo.id.trim() || null;

				if (!appId || !channel) {
					console.log("App ID 和频道名不能为空");
					return;
				}

				try {
					// showLoading("正在连接...");
					showToast("正在连接...")

					// 检查设备权限
					const [micDevices, cameraDevices] = await Promise.all([
						AgoraRTC.getMicrophones(),
						AgoraRTC.getCameras()
					]);

					if (micDevices.length === 0) {
						console.log('未找到麦克风设备');
						handleJoinError(userId, '未找到麦克风设备');
						return;
					}

					if (cameraDevices.length === 0) {
						console.log('未找到摄像头设备');
						showToast("未找到摄像头设备");
						// 继续连接，仅使用音频
					}

					console.log("正在初始化客户端...");
					AgoraRTC.setLogLevel(2); // 设置日志级别

					// 创建客户端
					client = AgoraRTC.createClient({
						mode: "rtc",
						codec: "vp8"
					});

					console.log("初始化成功", client);

					// 加入频道
					console.log("正在加入频道");
					const uid = await client.join(appId, channel, token || null, userId);
					console.log('本地用户ID', uid);

					// 设置事件监听
					setupClientEvents();


				} catch (error) {
					console.log(`加入频道失败: ${error.message}`);
					console.error(error);
					handleJoinError(userId, '连接失败');
					stopCallTimer();
				} finally {
					hideLoading();
				}
			}

			// 设置客户端事件监听
			 function setupClientEvents() {
				// 用户加入频道
				client.on("user-joined", async (user) => {
					console.log(`用户 ${user.uid} 加入了频道`);
					console.log('remoteUsers',client.remoteUsers)
					// 不需要立即处理，等待用户发布流
					if (client.remoteUsers.length >= 1) {
						// 发布本地音视频轨道
						await publishLocalTracks();
						// 显示群聊界面
						incomingCall.style.display = 'none';
						groupVideoCall.style.display = 'block';
					}
				});

				// 用户发布媒体流
				client.on("user-published", async (user, mediaType) => {
					console.log(`用户 ${user.uid} 发布了 ${mediaType} 流`);
					// 订阅远程用户
					await client.subscribe(user, mediaType);

					// 初始化远程用户信息
					if (!remoteUsers[user.uid]) {
						remoteUsers[user.uid] = {
							user: user,
							audioTrack: null,
							videoTrack: null,
							isSpeaking: false,
							speakingLevel: 0
						};
					}

					// 处理视频流
					if (mediaType === "video") {
						remoteUsers[user.uid].videoTrack = user.videoTrack;
						addRemoteVideo(user.uid);

						// 监听视频状态
						user.videoTrack.on("track-ended", () => {
							console.log(`用户 ${user.uid} 视频已结束`);
							removeRemoteVideo(user.uid);
						});
					}

					// 处理音频流
					if (mediaType === "audio") {
						remoteUsers[user.uid].audioTrack = user.audioTrack;
						user.audioTrack.play();

						// 监听音频状态
						user.audioTrack.on("track-ended", () => {
							console.log(`用户 ${user.uid} 音频已结束`);
							remoteUsers[user.uid].audioTrack = null;
							updateSpeakingStatus(user.uid, false);
						});
					}

					// 如果是第一个远程用户，开始计时
					if (Object.keys(remoteUsers).length === 1) {
						startCallTimer();
					}

					// 启用音量检测
					client.enableAudioVolumeIndicator();
					client.on("volume-indicator", (volumes) => {
						volumes.forEach((volume) => {
							if (volume.uid === userId) {
								// 本地用户音量
								updateLocalSpeakingStatus(volume.level > 5);
							} else if (remoteUsers[volume.uid]) {
								// 远程用户音量
								remoteUsers[volume.uid].speakingLevel = volume.level;
								remoteUsers[volume.uid].isSpeaking = volume.level > 5;

								// 更新说话状态
								updateSpeakingStatus(volume.uid, volume.level > 5);

								// 更新主说话人
								if (volume.level > 5 && (!currentMainSpeaker || volume.level > (remoteUsers[
										currentMainSpeaker]?.speakingLevel || 0))) {
									currentMainSpeaker = volume.uid;
									updateMainSpeaker();
								}
							}
						});
					});
				});

				// 用户取消发布媒体流
				client.on("user-unpublished", (user, mediaType) => {
					console.log(`用户 ${user.uid} 取消发布了 ${mediaType} 流`);

					if (mediaType === "video") {
						remoteUsers[user.uid].videoTrack = null;
						removeRemoteVideo(user.uid);
					}

					if (mediaType === "audio") {
						remoteUsers[user.uid].audioTrack = null;
						updateSpeakingStatus(user.uid, false);
					}

					// 如果用户取消了所有流，从远程用户列表中移除
					if (!remoteUsers[user.uid].audioTrack && !remoteUsers[user.uid].videoTrack) {
						delete remoteUsers[user.uid];

						// 如果主说话人离开，重置主说话人
						if (currentMainSpeaker === user.uid) {
							currentMainSpeaker = null;
							updateMainSpeaker();
						}
						if (remoteUsers.length > 0) {
							showToast(`${user.uid} 已离开`)
						} else {
							handeUp('')
						}
					}
				});

				// 用户离开频道
				client.on("user-left", (user) => {
					console.log(`用户 ${user.uid} 离开了频道`);

					// 从远程用户列表中移除
					delete remoteUsers[user.uid];

					// 移除对应的视频元素
					removeRemoteVideo(user.uid);

					// 如果主说话人离开，重置主说话人
					if (currentMainSpeaker === user.uid) {
						currentMainSpeaker = null;
						updateMainSpeaker();
					}
					if (remoteUsers.length > 0) {
						showToast(`${user.uid} 已离开`)
					} else {
						handeUp('')
					}
				});

				// 网络质量检测
				client.on("network-quality", (stats) => {
					// console.log('network-quality',stats)
					// 确保 stats 存在再使用
					if (stats) updateNetworkStatus(stats);
				});

				// 连接状态变化
				client.on("connection-state-change", (state, reason) => {
					console.log(`连接状态变化: ${state}, 原因: ${reason}`);
					if (state === "DISCONNECTED") {
						handeUp(userId);
					}
				});
			}

			// 发布本地音视频轨道
			async function publishLocalTracks() {
				try {
					// 创建本地音视频轨道
					[localAudioTrack, localVideoTrack] = await AgoraRTC.createMicrophoneAndCameraTracks({
						encoderConfig: "speech_standard",
						AEC: true,
						ANS: true
					}, {
						encoderConfig: "720p_1",
						facingMode: "user"
					});

					// 发布本地轨道
					await client.publish([localAudioTrack, localVideoTrack]);
					console.log("本地音视频发布成功");

					// 添加本地视频到成员列表
					addLocalVideo();

					// 监听本地音频音量变化
					localAudioTrack.on("volume-change", (volume) => {
						updateLocalSpeakingStatus(volume > 50);
					});

				} catch (error) {
					console.error("发布本地轨道失败:", error);

					// 尝试仅发布音频
					try {
						localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack({
							encoderConfig: "speech_standard",
							AEC: true,
							ANS: true
						});

						await client.publish([localAudioTrack]);
						console.log("本地音频发布成功");

						// 显示摄像头不可用提示
						showToast("摄像头不可用");

						// 添加本地用户到成员列表（仅音频）
						addLocalVideo(true);

					} catch (audioError) {
						console.error("发布本地音频失败:", audioError);
						handlePublishError(userId, '麦克风不可用');
						throw audioError;
					}
				}
			}

			// 添加本地视频到成员列表
			function addLocalVideo(audioOnly = false) {
				const videoItem = document.createElement('div');
				videoItem.className = 'member-video-item local-video';
				videoItem.id = `local-video-${userId}`;

				if (audioOnly) {
					videoItem.innerHTML = `
                    <div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:#333;">
                        <i class="fas fa-user" style="font-size:30px;color:#ccc;"></i>
                    </div>
                    <div class="member-info">
                        <div class="member-name">我</div>
                        <div class="member-status">
                            <div class="speaking-indicator"></div>
                            <i class="fas fa-microphone"></i>
                        </div>
                    </div>
                `;
				} else {
					videoItem.innerHTML = `
                    <video class="member-video" id="local-video-stream" autoplay playsinline muted></video>
                    <div class="member-info">
                        <div class="member-name">我</div>
                        <div class="member-status">
                            <div class="speaking-indicator"></div>
                            <i class="fas fa-microphone"></i>
                        </div>
                    </div>
                `;

					const localVideoStream = document.getElementById('local-video-stream');
					localVideoStream.srcObject = new MediaStream([localVideoTrack.getMediaStreamTrack()]);
				}

				memberVideos.appendChild(videoItem);
			}

			// 添加远程视频到成员列表
			function addRemoteVideo(uid) {
				if (!remoteUsers[uid] || !remoteUsers[uid].videoTrack) return;

				// 如果已经存在，先移除
				const existingVideo = document.getElementById(`remote-video-${uid}`);
				if (existingVideo) {
					existingVideo.remove();
				}

				const videoItem = document.createElement('div');
				videoItem.className = 'member-video-item remote-video';
				videoItem.id = `remote-video-${uid}`;

				videoItem.innerHTML = `
                <video class="member-video" autoplay playsinline></video>
                <div class="member-info">
                    <div class="member-name">${getUserName(uid)}</div>
                    <div class="member-status">
                        <div class="speaking-indicator"></div>
                        <i class="fas fa-microphone"></i>
                    </div>
                </div>
            `;

				const videoElement = videoItem.querySelector('video');
				videoElement.srcObject = new MediaStream([remoteUsers[uid].videoTrack.getMediaStreamTrack()]);

				// 点击成员视频切换主视图
				videoItem.addEventListener('click', () => {
					currentMainSpeaker = uid;
					updateMainSpeaker();
				});

				memberVideos.appendChild(videoItem);

				// 更新主说话人
				if (!currentMainSpeaker) {
					currentMainSpeaker = uid;
					updateMainSpeaker();
				}
			}

			// 移除远程视频
			function removeRemoteVideo(uid) {
				const videoElement = document.getElementById(`remote-video-${uid}`);
				if (videoElement) {
					videoElement.remove();
				}
			}

			// 更新主说话人视图
			function updateMainSpeaker() {
				if (currentMainSpeaker && remoteUsers[currentMainSpeaker] && remoteUsers[currentMainSpeaker].videoTrack) {
					// 显示远程用户为主说话人
					mainVideo.srcObject = new MediaStream([remoteUsers[currentMainSpeaker].videoTrack.getMediaStreamTrack()]);
				} else {
					// 没有主说话人或主说话人没有视频，显示本地视频
					if (localVideoTrack) {
						mainVideo.srcObject = new MediaStream([localVideoTrack.getMediaStreamTrack()]);
					} else {
						// 本地也没有视频，显示默认背景
						mainVideo.srcObject = null;
						mainVideo.style.backgroundColor = '#333';
					}
				}
			}

			// 更新说话状态
			function updateSpeakingStatus(uid, isSpeaking) {
				const videoItem = document.getElementById(`${uid === userId ? 'local' : 'remote'}-video-${uid}`);
				if (videoItem) {
					if (isSpeaking) {
						videoItem.classList.add('speaking');
					} else {
						videoItem.classList.remove('speaking');
					}
				}
			}

			// 更新本地说话状态
			function updateLocalSpeakingStatus(isSpeaking) {
				const localVideoItem = document.getElementById(`local-video-${userId}`);
				if (localVideoItem) {
					if (isSpeaking) {
						localVideoItem.classList.add('speaking');
					} else {
						localVideoItem.classList.remove('speaking');
					}
				}
			}

			// 更新远程音频音量
			function updateRemoteAudioVolume(volume) {
				Object.values(remoteUsers).forEach(user => {
					if (user.audioTrack) {
						user.audioTrack.setVolume(volume);
					}
				});
			}

			// 取消发布本地轨道
			async function unpublishLocalTracks() {
				try {
					if (client) {
						if (localAudioTrack) {
							await client.unpublish([localAudioTrack]);
							localAudioTrack.close();
							localAudioTrack = null;
						}

						if (localVideoTrack) {
							await client.unpublish([localVideoTrack]);
							localVideoTrack.close();
							localVideoTrack = null;
						}
					}
				} catch (error) {
					console.error("取消发布本地轨道失败:", error);
				}
			}

			// 离开频道
			async function leaveChannel() {
				if (!client) {
					console.log("客户端未初始化");
					return;
				}

				try {
					// 取消发布本地轨道
					await unpublishLocalTracks();

					// 离开频道
					await client.leave();
					client = null;

					console.log("成功离开频道");

					// 清理UI
					mainVideo.srcObject = null;
					memberVideos.innerHTML = '';
					remoteUsers = {};
					currentMainSpeaker = null;

				} catch (error) {
					console.error("离开频道失败:", error);
					throw error;
				} finally {
					forceCleanup();
				}
			}

			// 强制清理资源
			async function forceCleanup() {
				await unpublishLocalTracks();

				if (client) {
					try {
						await client.leave();
					} catch (e) {
						console.warn("强制离开频道时出错:", e);
					}
					client = null;
				}

				// 清理视频元素
				mainVideo.srcObject = null;
				memberVideos.innerHTML = '';
				remoteUsers = {};
				currentMainSpeaker = null;
			}

			// 根据用户ID获取用户名
			function getUserName(uid) {
				if (uid === userId) return '我';
				if (groupInfo.members) {
					const member = groupInfo.members.find(m => m.id === uid);
					if (member) return member.name;
				}
				return `用户${uid}`;
			}

			// 根据用户ID获取头像
			function getUserAvatar(uid) {
				if (uid === userId) return userInfo.avatar || 'https://via.placeholder.com/60/555/888';
				if (groupInfo.members) {
					const member = groupInfo.members.find(m => m.id === uid);
					if (member) return member.avatar;
				}
				return 'https://via.placeholder.com/60/333/666';
			}

			function handleJoinError(userId, error) {
				const call_request = {
					callerId: "groupVideoCall",
					status: false,
					timestamp: Date.now(),
					userId: userId,
					error: error
				};
				sendToUniApp(call_request);
			}

			function handlePublishError(userId, error) {
				const call_request = {
					callerId: "groupVideoCall",
					status: false,
					timestamp: Date.now(),
					userId: userId,
					error: error
				};
				sendToUniApp(call_request);
			}

			// 显示加载指示器
			function showLoading(message) {
				loadingIndicator.textContent = message;
				loadingIndicator.style.display = 'flex';
			}

			// 隐藏加载指示器
			function hideLoading() {
				loadingIndicator.style.display = 'none';
			}

			// 更新网络状态显示
			function updateNetworkStatus(stats) {
				let status = "网络良好";
				let color = "#34c759";

				// 下行网络质量
				if (stats.downlinkNetworkQuality > 4) {
					status = "网络较差";
					color = "#ff9500";
					showToast('网络较差');
				}
				if (stats.downlinkNetworkQuality > 6) {
					status = "网络非常差";
					color = "#ff3b30";
					showToast('网络非常差');
				}
			}

			// 提示框
			function showToast(message) {
				const toast = document.getElementById('toast');
				const toastMessage = document.getElementById('toastMessage');
				toastMessage.textContent = message;
				toast.classList.add('show');
				toast.classList.remove('hide');
				setTimeout(() => {
					toast.classList.remove('show');
					setTimeout(() => {
						toast.classList.add('hide');
					}, 300);
				}, 2000);
			}
		</script>
	</body>
</html>